List & Label can be used from multiple threads. This enables the distribution of large print jobs on multiple different processors / cores. Internally, this is used for the designer preview or drill down reporting. If you plan to use List & Label in a multithreaded environment, keep the following issues in mind.
Make sure that each List & Label job (resp. a component instance) is only used within a single thread, i.e. the creation, usage and destruction of the job/component needs to be done from the same thread. If you want to use multiple printing threads, each of these threads needs to open and close it's own job. Background: Windows GDI resources like window handles or printer device contexts cannot be used across different threads.
Make sure to open a job/create a component instance in your application before starting the first print thread and do not close this job before all threads are terminated. Typically, this will be done in your application's start-up and shutdown code. Background: the first job creates a couple of helper objects that need to be destroyed in the same job. Also, this can increase the performance remarkably as it avoids steady loading and unloading of DLLs.
Note: If List & Label is to work independently of printer drivers (usually in web applications etc.), the printerless mode can be activated for this purpose. The Printerless property must be set in the first object/protection job. A mixture of enabled and disabled printerless mode in the objects used in the application is not supported and can lead to unexpected behavior.
Threads that open the designer need to use the Single Threaded Apartment (STA) concurrency model. This means you cannot use .NET worker threads from the thread pool for this task, as they are initialized to use the Multi Threaded Apartment (MTA) concurrency model. Background: List & Label needs to call OleInitialize() for drag & drop support within the designer, which requires the current apartment to be STA to succeed.
The following code snippet covers all the important points mentioned above and simulates starting Reporting.StartApplication() and ending Reporting.ExitApplication() of an application. It is intended solely for simplified illustration and must be adapted to the specific circumstances/application.
It shows in detail how to use the protection job as _protectionJob. It is crucial that a new/fresh ListLabel instance (worker job) is always used for the main central functions Design, Print, or Export - the protection job is only kept in memory and is not actively used for any reporting functions.
In addition, a central routine CreateListLabel() is used to create the required ListLabel instances, always using central basic options such as the LicensingInfo property. This also makes it easier to update when changing versions.